Looking at the data

it looks like there might be a difference between the high and low debt groups, the variance is decidedly higher in the high debt group.

d.both_completed %>%
  ggplot(aes(x=sonarqube_issues, fill=high_debt_version)) + 
  geom_boxplot() +
  labs(
    title = "Number of issuess for the different debt levels",
    x ="Number of issues"
  ) +
  scale_y_continuous(breaks = NULL) +
  scale_fill_manual(
    name = "Debt level", 
    labels = c("High debt", "Low debt"), 
    values = c("#7070FF", "lightblue"), 
    guide = guide_legend(reverse = TRUE)
  ) 

Descriptive Statistics:

d.both_completed %>%
  pull(sonarqube_issues) %>% 
  summary()
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   1.000   1.659   3.000  12.000
sprintf("Variance: %.2f", var(pull(d.both_completed, sonarqube_issues)))
## [1] "Variance: 6.00"

Initial model

Variable names are modeled using the negative binomial family rather than poisson since the variance is greater than the mean.

We include high_debt_verison as a predictor in our model as this variable represent the very effect we want to measure. We also include a varying intercept for each individual to prevent the model from learning too much from single participants with extreme measurements.

Selecting Priors

We iterate over the model until we have sane priors, in this case a prior giving a 50/50 chance was chosen in both cases.

Base model with priors

sonarqube_issues.with <- extendable_model(
  base_name = "sonarqube_issues",
  base_formula = "sonarqube_issues ~ 1 + high_debt_version + (1 | session)",
  base_priors = c(
    prior(normal(0, 1), class = "b"),
    prior(normal(1.5, 1), class = "Intercept"),
    prior(exponential(1), class = "sd"),
    prior(gamma(0.01, 0.01), class = "shape")
  ),
  family = negbinomial(),
  data = d.both_completed,
  base_control = list(adapt_delta = 0.98)
)

Default priors

prior_summary(sonarqube_issues.with(only_priors= TRUE))

Selected priors

prior_summary(sonarqube_issues.with(sample_prior = "only"))

Prior Predictive Check

pp_check(sonarqube_issues.with(sample_prior = "only"), nsamples = 400, type = "bars")  + xlim(-1, 15)

Beta Parameter Influence

sim.size <- 1000
sim.intercept <- rnorm(sim.size, 1.5, 1)
sim.beta <- rnorm(sim.size, 0, 1)
sim.beta.diff <- exp(sim.intercept + sim.beta) - exp(sim.intercept)
sim.beta.diff.min <- sim.beta.diff

data.frame(x = sim.beta.diff.min) %>%
  ggplot(aes(x)) +
  geom_density() +
  xlim(-15, 15) +
  labs(
    title = "Beta parameter prior influence",
    x = "Issues difference",
    y = "Density"
  )

Model fit

We check the posterior distribution and can see that the model seems to have been able to fit the data well Sampling seems to also have worked well as Rhat values are close to 1 and the sampling plots look nice.

Posterior Predictive check

pp_check(sonarqube_issues.with(), nsamples = 200, type = "bars") + xlim(-1, 15)

Summary

summary(sonarqube_issues.with())
##  Family: negbinomial 
##   Links: mu = log; shape = identity 
## Formula: sonarqube_issues ~ 1 + high_debt_version + (1 | session) 
##    Data: as.data.frame(data) (Number of observations: 44) 
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup samples = 4000
## 
## Group-Level Effects: 
## ~session (Number of levels: 22) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.49      0.35     0.02     1.28 1.00     1081     1610
## 
## Population-Level Effects: 
##                        Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                  0.74      0.33     0.07     1.40 1.00     2981
## high_debt_versionfalse    -0.66      0.43    -1.48     0.20 1.00     6236
##                        Tail_ESS
## Intercept                  2646
## high_debt_versionfalse     2933
## 
## Family Specific Parameters: 
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## shape     1.20      3.03     0.32     4.35 1.00     1280      913
## 
## Samples were drawn using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Sampling plots

plot(sonarqube_issues.with(), ask = FALSE)

Model predictor extenstions

# default prior for monotonic predictor
edlvl_prior <- prior(dirichlet(2), class = "simo", coef = "moeducation_level1")

One variable

loo_result <- loo(
  # Benchmark model(s)
  sonarqube_issues.with(),
  # New model(s)
  sonarqube_issues.with("modified_lines"),
  sonarqube_issues.with("work_domain"),
  sonarqube_issues.with("work_experience_programming.s"),
  sonarqube_issues.with("work_experience_java.s"),
  sonarqube_issues.with("education_field"),
  sonarqube_issues.with("mo(education_level)", edlvl_prior),
  sonarqube_issues.with("workplace_peer_review"),
  sonarqube_issues.with("workplace_td_tracking"),
  sonarqube_issues.with("workplace_pair_programming"),
  sonarqube_issues.with("workplace_coding_standards"),
  sonarqube_issues.with("scenario"),
  sonarqube_issues.with("group")
)

Comparison

loo_result[2]
## $diffs
##                                                           elpd_diff se_diff
## sonarqube_issues.with("group")                             0.0       0.0   
## sonarqube_issues.with("work_domain")                      -0.7       2.1   
## sonarqube_issues.with()                                   -1.0       1.4   
## sonarqube_issues.with("workplace_coding_standards")       -1.2       1.4   
## sonarqube_issues.with("workplace_peer_review")            -1.4       1.3   
## sonarqube_issues.with("workplace_pair_programming")       -1.5       1.4   
## sonarqube_issues.with("mo(education_level)", edlvl_prior) -1.5       1.4   
## sonarqube_issues.with("scenario")                         -1.7       1.9   
## sonarqube_issues.with("workplace_td_tracking")            -1.7       1.5   
## sonarqube_issues.with("education_field")                  -2.0       1.6   
## sonarqube_issues.with("modified_lines")                   -2.1       1.5   
## sonarqube_issues.with("work_experience_programming.s")    -2.3       1.6   
## sonarqube_issues.with("work_experience_java.s")           -2.4       1.4

Diagnostics

loo_result[1]
## $loos
## $loos$`sonarqube_issues.with()`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -77.8  7.8
## p_loo         6.6  1.2
## looic       155.6 15.6
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     27    61.4%   687       
##  (0.5, 0.7]   (ok)       14    31.8%   203       
##    (0.7, 1]   (bad)       3     6.8%   664       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("modified_lines")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.9  7.9
## p_loo         7.6  1.4
## looic       157.8 15.8
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     27    61.4%   595       
##  (0.5, 0.7]   (ok)       12    27.3%   417       
##    (0.7, 1]   (bad)       5    11.4%   41        
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("work_domain")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -77.5  7.6
## p_loo         8.6  1.1
## looic       155.0 15.2
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     30    68.2%   1394      
##  (0.5, 0.7]   (ok)       12    27.3%   292       
##    (0.7, 1]   (bad)       2     4.5%   276       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("work_experience_programming.s")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -79.1  8.3
## p_loo         8.1  1.9
## looic       158.3 16.6
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     28    63.6%   1016      
##  (0.5, 0.7]   (ok)       12    27.3%   317       
##    (0.7, 1]   (bad)       3     6.8%   62        
##    (1, Inf)   (very bad)  1     2.3%   38        
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("work_experience_java.s")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -79.2  8.2
## p_loo         8.0  1.8
## looic       158.5 16.3
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     29    65.9%   340       
##  (0.5, 0.7]   (ok)       10    22.7%   66        
##    (0.7, 1]   (bad)       5    11.4%   28        
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("education_field")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.8  8.0
## p_loo         7.6  1.3
## looic       157.6 16.0
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     29    65.9%   716       
##  (0.5, 0.7]   (ok)       12    27.3%   107       
##    (0.7, 1]   (bad)       3     6.8%   421       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("mo(education_level)", edlvl_prior)`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.3  7.8
## p_loo         7.2  1.2
## looic       156.7 15.6
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     28    63.6%   969       
##  (0.5, 0.7]   (ok)       13    29.5%   322       
##    (0.7, 1]   (bad)       3     6.8%   89        
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("workplace_peer_review")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.3  7.9
## p_loo         7.1  1.3
## looic       156.5 15.9
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     26    59.1%   654       
##  (0.5, 0.7]   (ok)       17    38.6%   144       
##    (0.7, 1]   (bad)       1     2.3%   2579      
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("workplace_td_tracking")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.5  7.9
## p_loo         7.2  1.3
## looic       157.0 15.9
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     30    68.2%   662       
##  (0.5, 0.7]   (ok)       11    25.0%   255       
##    (0.7, 1]   (bad)       3     6.8%   75        
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("workplace_pair_programming")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.3  7.9
## p_loo         7.6  1.3
## looic       156.6 15.8
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     29    65.9%   418       
##  (0.5, 0.7]   (ok)       12    27.3%   48        
##    (0.7, 1]   (bad)       3     6.8%   151       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("workplace_coding_standards")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.0  8.1
## p_loo         8.0  1.6
## looic       156.0 16.2
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     31    70.5%   566       
##  (0.5, 0.7]   (ok)        7    15.9%   112       
##    (0.7, 1]   (bad)       6    13.6%   109       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("scenario")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -78.5  8.2
## p_loo         8.3  1.7
## looic       157.0 16.3
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     25    56.8%   601       
##  (0.5, 0.7]   (ok)       13    29.5%   109       
##    (0.7, 1]   (bad)       6    13.6%   50        
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## $loos$`sonarqube_issues.with("group")`
## 
## Computed from 4000 by 44 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -76.8  7.7
## p_loo         7.7  1.2
## looic       153.7 15.4
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     28    63.6%   1154      
##  (0.5, 0.7]   (ok)       13    29.5%   364       
##    (0.7, 1]   (bad)       3     6.8%   207       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.

Candidate models

We inspect some of our top performing models.

All models seems to have sampled nicely (rhat = 1 and fluffy plots) they also have about the same fit to the data and similar estimates for the high_debt_version beta parameter.

sonarqube_issues0

We select the simplest model as a baseline.

sonarqube_issues0 <- brm(
  "sonarqube_issues ~ 1 + high_debt_version + (1 | session)",
  prior = c(
    prior(normal(0, 1), class = "b"),
    prior(normal(1.5, 1), class = "Intercept"),
    prior(exponential(1), class = "sd"),
    prior(gamma(0.01, 0.01), class = "shape")
  ),
  family = negbinomial(),
  data = d.both_completed,
  control = list(adapt_delta = 0.97),
  file = "fits/sonarqube_issues0",
  file_refit = "on_change",
  seed = 20210421
)

Summary

summary(sonarqube_issues0)
##  Family: negbinomial 
##   Links: mu = log; shape = identity 
## Formula: sonarqube_issues ~ 1 + high_debt_version + (1 | session) 
##    Data: d.both_completed (Number of observations: 44) 
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup samples = 4000
## 
## Group-Level Effects: 
## ~session (Number of levels: 22) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.49      0.35     0.02     1.27 1.00      746     1243
## 
## Population-Level Effects: 
##                        Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                  0.74      0.32     0.12     1.40 1.00     2608
## high_debt_versionfalse    -0.65      0.44    -1.51     0.23 1.00     4220
##                        Tail_ESS
## Intercept                  2464
## high_debt_versionfalse     2595
## 
## Family Specific Parameters: 
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## shape     1.08      1.66     0.31     3.43 1.00     1193      993
## 
## Samples were drawn using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Random effects

ranef(sonarqube_issues0)
## $session
## , , Intercept
## 
##                              Estimate Est.Error       Q2.5     Q97.5
## 6033d69a5af2c702367b3a95 -0.015426533 0.4532342 -0.9601534 0.9665391
## 6033d90a5af2c702367b3a96 -0.182111985 0.5247973 -1.4499718 0.7352185
## 6034fc165af2c702367b3a98  0.423284174 0.5469530 -0.3145141 1.7514600
## 603500725af2c702367b3a99 -0.151292373 0.5266088 -1.4593530 0.7825570
## 603f97625af2c702367b3a9d  0.434497996 0.5543786 -0.3000722 1.7628220
## 603fd5d95af2c702367b3a9e -0.043145124 0.4814010 -1.1429757 1.0077323
## 60409b7b5af2c702367b3a9f  0.223344768 0.4964740 -0.5677460 1.4698325
## 604b82b5a7718fbed181b336  0.374030701 0.5312487 -0.3717971 1.6742650
## 6050c1bf856f36729d2e5218 -0.138884597 0.5114334 -1.3611878 0.7969012
## 6050e1e7856f36729d2e5219  0.069333409 0.4480372 -0.7984438 1.1141293
## 6055fdc6856f36729d2e521b  0.132388707 0.4529984 -0.6950727 1.1976780
## 60589862856f36729d2e521f -0.291359806 0.6137007 -1.9097217 0.6457119
## 605afa3a856f36729d2e5222 -0.291471601 0.6287735 -1.9157843 0.6660266
## 605c8bc6856f36729d2e5223 -0.003762474 0.4555736 -0.9791205 1.0302080
## 605f3f2d856f36729d2e5224  0.090931779 0.4436929 -0.7612083 1.1819968
## 605f46c3856f36729d2e5225 -0.287443157 0.6158478 -1.8847050 0.6370332
## 60605337856f36729d2e5226 -0.287239287 0.6356421 -1.8549045 0.7020783
## 60609ae6856f36729d2e5228 -0.074123451 0.4691407 -1.1307098 0.8682720
## 6061ce91856f36729d2e522e -0.149444875 0.5170214 -1.4375312 0.8059823
## 6061f106856f36729d2e5231 -0.298277320 0.6191952 -1.8935122 0.6283760
## 6068ea9f856f36729d2e523e -0.029443952 0.4563865 -1.0217985 0.9418743
## 6075ab05856f36729d2e5247  0.054512901 0.4567384 -0.8394841 1.0704043

Sampling plots

plot(sonarqube_issues0, ask = FALSE)

Posterior predictive check

pp_check(sonarqube_issues0, nsamples = 200, type = "bars")  + xlim(-1, 15)

sonarqube_issues1

We select the best performing model with one variable.

sonarqube_issues1 <- brm(
  "sonarqube_issues ~ 1 + high_debt_version + (1 | session) + group",
  prior = c(
    prior(normal(0, 1), class = "b"),
    prior(normal(1.5, 1), class = "Intercept"),
    prior(exponential(1), class = "sd"),
    prior(gamma(0.01, 0.01), class = "shape")
  ),
  family = negbinomial(),
  data = d.both_completed,
  control = list(adapt_delta = 0.97),
  file = "fits/sonarqube_issues1",
  file_refit = "on_change",
  seed = 20210421
)

Summary

summary(sonarqube_issues1)
##  Family: negbinomial 
##   Links: mu = log; shape = identity 
## Formula: sonarqube_issues ~ 1 + high_debt_version + (1 | session) + group 
##    Data: d.both_completed (Number of observations: 44) 
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup samples = 4000
## 
## Group-Level Effects: 
## ~session (Number of levels: 22) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.44      0.32     0.02     1.17 1.00     1174     1650
## 
## Population-Level Effects: 
##                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                     0.29      0.44    -0.55     1.17 1.00     4454
## high_debt_versionfalse       -0.67      0.42    -1.50     0.16 1.00     6103
## groupconsultants              0.76      0.59    -0.39     1.90 1.00     4848
## groupfriends                  0.07      0.58    -1.08     1.19 1.00     4771
## groupprofessionalMcontact    -0.57      0.87    -2.26     1.09 1.00     7240
## groupstudents                 0.84      0.52    -0.22     1.88 1.00     4688
##                           Tail_ESS
## Intercept                     2958
## high_debt_versionfalse        2733
## groupconsultants              3523
## groupfriends                  3096
## groupprofessionalMcontact     3064
## groupstudents                 3145
## 
## Family Specific Parameters: 
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## shape     1.39      3.46     0.34     5.01 1.00     1534     1168
## 
## Samples were drawn using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).

Random effects

ranef(sonarqube_issues1)
## $session
## , , Intercept
## 
##                              Estimate Est.Error       Q2.5     Q97.5
## 6033d69a5af2c702367b3a95 -0.081304183 0.4154695 -1.0507785 0.7185234
## 6033d90a5af2c702367b3a96 -0.207906216 0.5102610 -1.4961468 0.6337217
## 6034fc165af2c702367b3a98  0.285987844 0.4863475 -0.4684298 1.4921308
## 603500725af2c702367b3a99 -0.184409027 0.4879314 -1.3795912 0.6398960
## 603f97625af2c702367b3a9d  0.299337913 0.4848486 -0.3827799 1.5155103
## 603fd5d95af2c702367b3a9e -0.103707031 0.4516897 -1.2147470 0.7275142
## 60409b7b5af2c702367b3a9f  0.108857629 0.4217302 -0.6752135 1.1723715
## 604b82b5a7718fbed181b336  0.247295591 0.4689723 -0.4925896 1.4309938
## 6050c1bf856f36729d2e5218 -0.087359199 0.4740323 -1.1862427 0.8285805
## 6050e1e7856f36729d2e5219  0.147007605 0.4636384 -0.6660956 1.2719775
## 6055fdc6856f36729d2e521b  0.187719395 0.4738022 -0.6160901 1.3604608
## 60589862856f36729d2e521f -0.224264352 0.5592673 -1.6365107 0.6419202
## 605afa3a856f36729d2e5222 -0.167676956 0.5259302 -1.4880422 0.7405240
## 605c8bc6856f36729d2e5223  0.063002012 0.4234574 -0.8043535 1.0550375
## 605f3f2d856f36729d2e5224  0.193235530 0.4475086 -0.5283976 1.2881588
## 605f46c3856f36729d2e5225 -0.222059466 0.5523469 -1.5863270 0.6798019
## 60605337856f36729d2e5226 -0.222071079 0.5373562 -1.5855955 0.6186339
## 60609ae6856f36729d2e5228 -0.009862025 0.4439996 -0.9824828 0.9317650
## 6061ce91856f36729d2e522e -0.081482112 0.4663235 -1.1329120 0.8743682
## 6061f106856f36729d2e5231 -0.234384020 0.5445859 -1.6376065 0.6042225
## 6068ea9f856f36729d2e523e -0.068876149 0.4360224 -1.0744567 0.8206025
## 6075ab05856f36729d2e5247 -0.029421582 0.4082587 -0.9089109 0.8547237

Sampling plots

plot(sonarqube_issues1, ask = FALSE)

Posterior predictive check

pp_check(sonarqube_issues1, nsamples = 200, type = "bars") + xlim(-1, 15)

Final Model

All candidate models look nice, none is significantly better than the others, we will proceed the simplest model: sonarqube_issues0

Variations

We will try a few different variations of the selected candidate model.

All data points

Some participants did only complete one scenario. Those has been excluded from the initial dataset to improve sampling of the models. We do however want to use all data we can and will therefore try to fit the model with the complete dataset.

sonarqube_issues0.all <- brm(
  "sonarqube_issues ~ 1 + high_debt_version + (1 | session)",
  prior = c(
    prior(normal(0, 1), class = "b"),
    prior(normal(1.5, 1), class = "Intercept"),
    prior(exponential(1), class = "sd"),
    prior(gamma(0.01, 0.01), class = "shape")
  ),
  family = negbinomial(),
  data = as.data.frame(d.completed),
  control = list(adapt_delta = 0.97),
  file = "fits/sonarqube_issues0.all",
  file_refit = "on_change",
  seed = 20210421
)
Summary
summary(sonarqube_issues0.all)
##  Family: negbinomial 
##   Links: mu = log; shape = identity 
## Formula: sonarqube_issues ~ 1 + high_debt_version + (1 | session) 
##    Data: as.data.frame(d.completed) (Number of observations: 51) 
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup samples = 4000
## 
## Group-Level Effects: 
## ~session (Number of levels: 29) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.49      0.32     0.02     1.18 1.01      743     1851
## 
## Population-Level Effects: 
##                        Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
## Intercept                  0.72      0.31     0.11     1.34 1.00     2339
## high_debt_versionfalse    -0.75      0.37    -1.48    -0.01 1.00     5947
##                        Tail_ESS
## Intercept                  2521
## high_debt_versionfalse     3117
## 
## Family Specific Parameters: 
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## shape     2.17      8.60     0.40     9.17 1.00      977      670
## 
## Samples were drawn using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
Random effects
ranef(sonarqube_issues0.all)
## $session
## , , Intercept
## 
##                              Estimate Est.Error       Q2.5     Q97.5
## 6033c6fc5af2c702367b3a93  0.183040574 0.4889970 -0.6813311 1.3516260
## 6033d69a5af2c702367b3a95 -0.022249127 0.4556012 -0.9854840 0.9080399
## 6033d90a5af2c702367b3a96 -0.196944157 0.5188610 -1.4218062 0.7026811
## 6034fc165af2c702367b3a98  0.502413581 0.5656409 -0.2667781 1.8094462
## 603500725af2c702367b3a99 -0.156376146 0.4976038 -1.3184595 0.7737207
## 603f84f15af2c702367b3a9b  0.016367782 0.5051662 -1.0735628 1.1059288
## 603f97625af2c702367b3a9d  0.515408470 0.5721404 -0.2452590 1.8393040
## 603fd5d95af2c702367b3a9e -0.038504466 0.4519691 -1.0056673 0.8989632
## 60409b7b5af2c702367b3a9f  0.267869109 0.4855030 -0.5005796 1.4388090
## 604b82b5a7718fbed181b336  0.447229396 0.5358051 -0.2770527 1.6917425
## 604f1239a7718fbed181b33f -0.092856028 0.5027129 -1.2195323 0.9058201
## 6050c1bf856f36729d2e5218 -0.162251344 0.4868765 -1.3203645 0.7324989
## 6050e1e7856f36729d2e5219  0.095917928 0.4364640 -0.7396285 1.1013025
## 6055fdc6856f36729d2e521b  0.145725621 0.4525242 -0.7093635 1.1793200
## 60579f2a856f36729d2e521e -0.003263625 0.4961099 -1.0781715 1.0466290
## 60589862856f36729d2e521f -0.326339237 0.6118806 -1.9140853 0.5758993
## 605a30a7856f36729d2e5221 -0.159213909 0.5565989 -1.5253892 0.8176027
## 605afa3a856f36729d2e5222 -0.327880912 0.5971902 -1.8445310 0.5400549
## 605c8bc6856f36729d2e5223 -0.012246897 0.4433745 -0.9728114 0.9410496
## 605f3f2d856f36729d2e5224  0.127173044 0.4403228 -0.7162329 1.1216853
## 605f46c3856f36729d2e5225 -0.322431071 0.5804321 -1.7840608 0.5545071
## 60605337856f36729d2e5226 -0.321573439 0.5982842 -1.8468108 0.6160728
## 60609ae6856f36729d2e5228 -0.088924633 0.4779361 -1.1629988 0.8648741
## 6061ce91856f36729d2e522e -0.158527485 0.5030132 -1.3385997 0.7616958
## 6061f106856f36729d2e5231 -0.331280152 0.5782342 -1.7966120 0.5220248
## 60672faa856f36729d2e523c  0.003455516 0.4977603 -1.0466032 1.0487368
## 6068ea9f856f36729d2e523e -0.014497613 0.4434550 -0.9308466 0.9263245
## 606db69d856f36729d2e5243 -0.155764875 0.5681107 -1.4736105 0.8840138
## 6075ab05856f36729d2e5247  0.069091587 0.4502341 -0.8264055 1.1139903
Sampling plots
plot(sonarqube_issues0.all, ask = FALSE)

Posterior predictive check
pp_check(sonarqube_issues0.all, nsamples = 200, type = "bars") + xlim(-1, 15)

With experience predictor

As including all data points didn’t harm the model we will create this variant with all data points as well.

This variation includes work_experience_programming.s predictors as it can give further insight into how experience play a factor in the effect we try to measure. This is especially important as our sampling shewed towards containing less experienced developer than the population at large.

sonarqube_issues0.all.exp <- brm(
  "sonarqube_issues ~ 1 + high_debt_version + (1 | session) + work_experience_programming.s",
  prior = c(
    prior(normal(0, 1), class = "b"),
    prior(normal(1.5, 1), class = "Intercept"),
    prior(exponential(1), class = "sd"),
    prior(gamma(0.01, 0.01), class = "shape")
  ),
  family = negbinomial(),
  data = as.data.frame(d.completed),
  control = list(adapt_delta = 0.99),
  file = "fits/sonarqube_issues0.all.exp",
  file_refit = "on_change",
  seed = 20210421
)
Summary
summary(sonarqube_issues0.all.exp)
##  Family: negbinomial 
##   Links: mu = log; shape = identity 
## Formula: sonarqube_issues ~ 1 + high_debt_version + (1 | session) + work_experience_programming.s 
##    Data: as.data.frame(d.completed) (Number of observations: 51) 
## Samples: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
##          total post-warmup samples = 4000
## 
## Group-Level Effects: 
## ~session (Number of levels: 29) 
##               Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## sd(Intercept)     0.47      0.32     0.02     1.16 1.01      781     1359
## 
## Population-Level Effects: 
##                               Estimate Est.Error l-95% CI u-95% CI Rhat
## Intercept                         0.73      0.30     0.15     1.32 1.00
## high_debt_versionfalse           -0.80      0.37    -1.53    -0.08 1.00
## work_experience_programming.s    -0.23      0.23    -0.68     0.23 1.00
##                               Bulk_ESS Tail_ESS
## Intercept                         2420     2532
## high_debt_versionfalse            5619     3043
## work_experience_programming.s     3615     2923
## 
## Family Specific Parameters: 
##       Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
## shape     1.42      2.55     0.40     4.90 1.00     1159     1073
## 
## Samples were drawn using sample(hmc). For each parameter, Bulk_ESS
## and Tail_ESS are effective sample size measures, and Rhat is the potential
## scale reduction factor on split chains (at convergence, Rhat = 1).
Random effects
ranef(sonarqube_issues0.all.exp)
## $session
## , , Intercept
## 
##                              Estimate Est.Error       Q2.5     Q97.5
## 6033c6fc5af2c702367b3a93  0.150231302 0.4893809 -0.7384628 1.3181015
## 6033d69a5af2c702367b3a95 -0.027721224 0.4465065 -0.9919532 0.9511171
## 6033d90a5af2c702367b3a96 -0.212867421 0.5167692 -1.4688272 0.6795067
## 6034fc165af2c702367b3a98  0.441811811 0.5364383 -0.2704206 1.7214052
## 603500725af2c702367b3a99 -0.166824801 0.4953391 -1.3589010 0.6924000
## 603f84f15af2c702367b3a9b -0.005408170 0.5000125 -1.1090082 1.0872495
## 603f97625af2c702367b3a9d  0.450718850 0.5441883 -0.2732800 1.7426025
## 603fd5d95af2c702367b3a9e -0.050682887 0.4607171 -1.1169910 0.8997919
## 60409b7b5af2c702367b3a9f  0.209953510 0.4697568 -0.5563558 1.3750000
## 604b82b5a7718fbed181b336  0.386380117 0.5118369 -0.3290899 1.6210893
## 604f1239a7718fbed181b33f -0.097352265 0.5259049 -1.3641330 0.8918844
## 6050c1bf856f36729d2e5218 -0.125149604 0.4858464 -1.2585625 0.7958516
## 6050e1e7856f36729d2e5219  0.081740545 0.4238045 -0.7271722 1.0743633
## 6055fdc6856f36729d2e521b  0.124592900 0.4369941 -0.6907562 1.1548175
## 60579f2a856f36729d2e521e  0.012462978 0.4872208 -1.0209262 1.0699733
## 60589862856f36729d2e521f -0.240040820 0.5723541 -1.6974480 0.6853926
## 605a30a7856f36729d2e5221 -0.145676166 0.5365815 -1.5214890 0.8356764
## 605afa3a856f36729d2e5222 -0.251102645 0.5557672 -1.5989025 0.6822767
## 605c8bc6856f36729d2e5223  0.005569367 0.4363755 -0.9154745 0.9611533
## 605f3f2d856f36729d2e5224  0.338293165 0.6121759 -0.5680731 1.8387200
## 605f46c3856f36729d2e5225 -0.300629687 0.5846514 -1.7749187 0.5449995
## 60605337856f36729d2e5226 -0.308509428 0.5801745 -1.7677882 0.5886754
## 60609ae6856f36729d2e5228 -0.109431355 0.4635303 -1.1715705 0.7831926
## 6061ce91856f36729d2e522e -0.163819830 0.5219103 -1.4126383 0.8137790
## 6061f106856f36729d2e5231 -0.303289256 0.5709239 -1.7602297 0.6000055
## 60672faa856f36729d2e523c  0.007519247 0.4901510 -1.0453803 1.0641403
## 6068ea9f856f36729d2e523e -0.012802872 0.4535053 -0.9922452 0.9685848
## 606db69d856f36729d2e5243 -0.121847161 0.5310919 -1.3890695 0.8916657
## 6075ab05856f36729d2e5247  0.042883483 0.4196267 -0.7868627 0.9914372
Loo comparison
loo(
  sonarqube_issues0.all,
  sonarqube_issues0.all.exp
)
## Output of model 'sonarqube_issues0.all':
## 
## Computed from 4000 by 51 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -88.0  8.1
## p_loo         8.3  1.6
## looic       176.1 16.2
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     31    60.8%   476       
##  (0.5, 0.7]   (ok)       16    31.4%   190       
##    (0.7, 1]   (bad)       4     7.8%   129       
##    (1, Inf)   (very bad)  0     0.0%   <NA>      
## See help('pareto-k-diagnostic') for details.
## 
## Output of model 'sonarqube_issues0.all.exp':
## 
## Computed from 4000 by 51 log-likelihood matrix
## 
##          Estimate   SE
## elpd_loo    -89.6  8.9
## p_loo         9.9  2.7
## looic       179.2 17.8
## ------
## Monte Carlo SE of elpd_loo is NA.
## 
## Pareto k diagnostic values:
##                          Count Pct.    Min. n_eff
## (-Inf, 0.5]   (good)     34    66.7%   704       
##  (0.5, 0.7]   (ok)       13    25.5%   315       
##    (0.7, 1]   (bad)       3     5.9%   130       
##    (1, Inf)   (very bad)  1     2.0%   10        
## See help('pareto-k-diagnostic') for details.
## 
## Model comparisons:
##                           elpd_diff se_diff
## sonarqube_issues0.all      0.0       0.0   
## sonarqube_issues0.all.exp -1.6       2.6
Sampling plots
plot(sonarqube_issues0.all.exp, ask = FALSE)

Posterior predictive check
pp_check(sonarqube_issues0.all.exp, nsamples = 200, type = "bars") + xlim(-1, 15)

Final model

  • Fitting the model to all data point did not significantly damage the model and will be used as is a more fair representation of reality.
  • Adding the experience predictors did not significantly damage the model and will be used as it provides useful insight.

This means that our final model, with all data points and experience predictors, is sonarqube_issues0.all.exp

Interpreting the model

To begin interpreting the model we look at how it’s parameters were estimated. As our research is focused on how the outcome of the model is effected we will mainly analyze the \(\beta\) parameters.

\(\beta\) parameters

mcmc_areas(sonarqube_issues0.all.exp, pars = c("b_high_debt_versionfalse", "b_work_experience_programming.s"), prob = 0.95) + scale_y_discrete() +
  scale_y_discrete(labels=c("High debt version: false", "Professional programming experience")) +
  ggtitle("Beta parameters densities in sonarqube issues model", subtitle = "Shaded region marks 95% of the density. Line marks the median")

Effects sizes

scale_programming_experience <- function(x) {
  (x - mean(d.completed$work_experience_programming))/ sd(d.completed$work_experience_programming)
}
unscale_programming_experience <- function(x) {
  x * sd(d.completed$work_experience_programming) + mean(d.completed$work_experience_programming)
}

post_settings <- expand.grid(
  high_debt_version = c("false", "true"),
  session = NA,
  work_experience_programming.s = sapply(c(0, 3, 10, 25, 40), scale_programming_experience)
)

post <- posterior_predict(sonarqube_issues0.all.exp, newdata = post_settings) %>%
  melt(value.name = "estimate", varnames = c("sample_number", "settings_id")) %>%
  left_join(
    rowid_to_column(post_settings, var= "settings_id"),
    by = "settings_id"
  ) %>%
  mutate(work_experience_programming = unscale_programming_experience(work_experience_programming.s)) %>%
  select(
    estimate,
    high_debt_version,
    work_experience_programming
  )%>%
  mutate(estimate = estimate)

ggplot(post, aes(x=estimate, fill = high_debt_version)) +
  geom_bar(position = "dodge2") +
  scale_fill_manual(
    name = "Debt version",
    labels = c("Low debt", "High debt"),
      values = c("lightblue", "darkblue")
  ) +
  facet_grid(rows = vars(work_experience_programming)) +
  labs(
    title = "SonarQube issues introduced / years of programming experience",
    subtitle = "Estimated for five different experience levels",
    x = "Issued introduced",
    y = "Incidence rate"
  ) + 
  xlim(-1, 10) + 
  scale_x_continuous(limits = c(-1,7), breaks = c(0,1,2,3,4,5,6,7), labels = c("0","1","2","3","4","5","6","7")) +
  scale_y_continuous(limits = NULL, breaks = c(500,1500,2500), labels = c("10%","30%","50%")) + 
  theme(legend.position = "top")

post.diff <- post %>% filter(high_debt_version == "true")
post.diff$estimate = post.diff$estimate -  filter(post, high_debt_version == "false")$estimate

ggplot(post.diff, aes(x=estimate)) +
  geom_boxplot(quantile_lines = TRUE, quantile_fun = hdi, vline_linetype = 2) +
  xlim(-7, 7) +
  facet_grid(rows = vars(work_experience_programming)) +
  labs(
    title = "SonarQube issues introduced difference / years of programming experience",
    subtitle = "Difference as: high debt issues - low debt issues",
    x = "Issues # difference"
  ) +
  scale_y_continuous(breaks = NULL)

print("All:")
## [1] "All:"
mean(post.diff$estimate)
## [1] 1.1694
print("3 years:")
## [1] "3 years:"
mean(post.diff %>% filter(work_experience_programming == 3) %>% pull(estimate))
## [1] 1.44725
print("25 years:")
## [1] "25 years:"
mean(post.diff %>% filter(work_experience_programming == 25) %>% pull(estimate))
## [1] 0.93

In the context of the assignment the participant were given, preexisting technical debt caused developers to on average introduce 1.18 sonarqube issues more. The effect varies with the professional programming experience of the developer with an average of 1.33 for those with 3 years of experience and an average of 0.87 for those with 25 years of experience.

LS0tCnRpdGxlOiAiU29uYXJRdWJlIElzc3VlcyBNb2RlbCIKYXV0aG9yOiBIYW1wdXMgQnJvbWFuICYgV2lsbGlhbSBMZXbDqW4KZGF0ZTogMjAyMS0wNQpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgcGFuZG9jX2FyZ3M6IFsgIi1vIiwgImRvY3Mvc29uYXJxdWJlX2lzc3Vlcy5odG1sIiBdCi0tLQoKYGBge3IgaW5jbHVkZS1zZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBMb2FkIHNldHVwIGZpbGUKc291cmNlKGtuaXRyOjpwdXJsKCdzZXR1cC5SbWQnLCBvdXRwdXQgPSB0ZW1wZmlsZSgpKSkKYGBgCgojIyBMb29raW5nIGF0IHRoZSBkYXRhIHsudGFic2V0fQppdCBsb29rcyBsaWtlIHRoZXJlIG1pZ2h0IGJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBoaWdoIGFuZCBsb3cgZGVidCBncm91cHMsIHRoZSB2YXJpYW5jZSBpcyBkZWNpZGVkbHkgaGlnaGVyIGluIHRoZSBoaWdoIGRlYnQgZ3JvdXAuCgpgYGB7ciBwbG90LTF9CmQuYm90aF9jb21wbGV0ZWQgJT4lCiAgZ2dwbG90KGFlcyh4PXNvbmFycXViZV9pc3N1ZXMsIGZpbGw9aGlnaF9kZWJ0X3ZlcnNpb24pKSArIAogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiTnVtYmVyIG9mIGlzc3Vlc3MgZm9yIHRoZSBkaWZmZXJlbnQgZGVidCBsZXZlbHMiLAogICAgeCA9Ik51bWJlciBvZiBpc3N1ZXMiCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IE5VTEwpICsKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIG5hbWUgPSAiRGVidCBsZXZlbCIsIAogICAgbGFiZWxzID0gYygiSGlnaCBkZWJ0IiwgIkxvdyBkZWJ0IiksIAogICAgdmFsdWVzID0gYygiIzcwNzBGRiIsICJsaWdodGJsdWUiKSwgCiAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkKICApIApgYGAKCiMjIERlc2NyaXB0aXZlIFN0YXRpc3RpY3M6CmBgYHtyIGRlc2NyaXB0aXZlLXN0YXRpc3RpY3N9CmQuYm90aF9jb21wbGV0ZWQgJT4lCiAgcHVsbChzb25hcnF1YmVfaXNzdWVzKSAlPiUgCiAgc3VtbWFyeSgpCgpzcHJpbnRmKCJWYXJpYW5jZTogJS4yZiIsIHZhcihwdWxsKGQuYm90aF9jb21wbGV0ZWQsIHNvbmFycXViZV9pc3N1ZXMpKSkKYGBgCgojIyBJbml0aWFsIG1vZGVsClZhcmlhYmxlIG5hbWVzIGFyZSBtb2RlbGVkIHVzaW5nIHRoZSBuZWdhdGl2ZSBiaW5vbWlhbCBmYW1pbHkgcmF0aGVyIHRoYW4gcG9pc3NvbiBzaW5jZSB0aGUgdmFyaWFuY2UgaXMgZ3JlYXRlciB0aGFuIHRoZSBtZWFuLgoKV2UgaW5jbHVkZSBgaGlnaF9kZWJ0X3Zlcmlzb25gIGFzIGEgcHJlZGljdG9yIGluIG91ciBtb2RlbCBhcyB0aGlzIHZhcmlhYmxlIHJlcHJlc2VudCB0aGUgdmVyeSBlZmZlY3Qgd2Ugd2FudCB0byBtZWFzdXJlLgpXZSBhbHNvIGluY2x1ZGUgYSB2YXJ5aW5nIGludGVyY2VwdCBmb3IgZWFjaCBpbmRpdmlkdWFsIHRvIHByZXZlbnQgdGhlIG1vZGVsIGZyb20gbGVhcm5pbmcgdG9vIG11Y2ggZnJvbSBzaW5nbGUgcGFydGljaXBhbnRzIHdpdGggZXh0cmVtZSBtZWFzdXJlbWVudHMuCgojIyMgU2VsZWN0aW5nIFByaW9ycyB7LnRhYnNldH0KCldlIGl0ZXJhdGUgb3ZlciB0aGUgbW9kZWwgdW50aWwgd2UgaGF2ZSBzYW5lIHByaW9ycywgaW4gdGhpcyBjYXNlIGEgcHJpb3IgZ2l2aW5nIGEgNTAvNTAgY2hhbmNlIHdhcyBjaG9zZW4gaW4gYm90aCBjYXNlcy4KCiMjIyMgQmFzZSBtb2RlbCB3aXRoIHByaW9ycwoKYGBge3IgaW5pdGlhbC1tb2RlbC1kZWZpbml0aW9uLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30Kc29uYXJxdWJlX2lzc3Vlcy53aXRoIDwtIGV4dGVuZGFibGVfbW9kZWwoCiAgYmFzZV9uYW1lID0gInNvbmFycXViZV9pc3N1ZXMiLAogIGJhc2VfZm9ybXVsYSA9ICJzb25hcnF1YmVfaXNzdWVzIH4gMSArIGhpZ2hfZGVidF92ZXJzaW9uICsgKDEgfCBzZXNzaW9uKSIsCiAgYmFzZV9wcmlvcnMgPSBjKAogICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9ICJiIiksCiAgICBwcmlvcihub3JtYWwoMS41LCAxKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3MgPSAic2QiKSwKICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9ICJzaGFwZSIpCiAgKSwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBkLmJvdGhfY29tcGxldGVkLAogIGJhc2VfY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjk4KQopCmBgYAoKIyMjIyBEZWZhdWx0IHByaW9ycwoKYGBge3IgZGVmYXVsdC1wcmlvcnN9CnByaW9yX3N1bW1hcnkoc29uYXJxdWJlX2lzc3Vlcy53aXRoKG9ubHlfcHJpb3JzPSBUUlVFKSkKYGBgCiMjIyMgU2VsZWN0ZWQgcHJpb3JzCgpgYGB7ciBzZWxlY3RlZC1wcmlvcnN9CnByaW9yX3N1bW1hcnkoc29uYXJxdWJlX2lzc3Vlcy53aXRoKHNhbXBsZV9wcmlvciA9ICJvbmx5IikpCmBgYAoKIyMjIyBQcmlvciBQcmVkaWN0aXZlIENoZWNrCgpgYGB7ciBwcmlvcnMtY2hlY2ssIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBwX2NoZWNrKHNvbmFycXViZV9pc3N1ZXMud2l0aChzYW1wbGVfcHJpb3IgPSAib25seSIpLCBuc2FtcGxlcyA9IDQwMCwgdHlwZSA9ICJiYXJzIikgICsgeGxpbSgtMSwgMTUpCmBgYAoKIyMjIyBCZXRhIFBhcmFtZXRlciBJbmZsdWVuY2UKCmBgYHtyIHByaW9ycy1iZXRhLCB3YXJuaW5nPUZBTFNFfQpzaW0uc2l6ZSA8LSAxMDAwCnNpbS5pbnRlcmNlcHQgPC0gcm5vcm0oc2ltLnNpemUsIDEuNSwgMSkKc2ltLmJldGEgPC0gcm5vcm0oc2ltLnNpemUsIDAsIDEpCnNpbS5iZXRhLmRpZmYgPC0gZXhwKHNpbS5pbnRlcmNlcHQgKyBzaW0uYmV0YSkgLSBleHAoc2ltLmludGVyY2VwdCkKc2ltLmJldGEuZGlmZi5taW4gPC0gc2ltLmJldGEuZGlmZgoKZGF0YS5mcmFtZSh4ID0gc2ltLmJldGEuZGlmZi5taW4pICU+JQogIGdncGxvdChhZXMoeCkpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgeGxpbSgtMTUsIDE1KSArCiAgbGFicygKICAgIHRpdGxlID0gIkJldGEgcGFyYW1ldGVyIHByaW9yIGluZmx1ZW5jZSIsCiAgICB4ID0gIklzc3VlcyBkaWZmZXJlbmNlIiwKICAgIHkgPSAiRGVuc2l0eSIKICApCgpgYGAKCiMjIyBNb2RlbCBmaXQgIHsudGFic2V0fQpXZSBjaGVjayB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBhbmQgY2FuIHNlZSB0aGF0IHRoZSBtb2RlbCBzZWVtcyB0byBoYXZlIGJlZW4gYWJsZSB0byBmaXQgdGhlIGRhdGEgd2VsbApTYW1wbGluZyBzZWVtcyB0byBhbHNvIGhhdmUgd29ya2VkIHdlbGwgYXMgUmhhdCB2YWx1ZXMgYXJlIGNsb3NlIHRvIDEgYW5kIHRoZSBzYW1wbGluZyBwbG90cyBsb29rIG5pY2UuCgojIyMjIFBvc3RlcmlvciBQcmVkaWN0aXZlIGNoZWNrCgpgYGB7ciBiYXNlLXBwLWNoZWNrLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwcF9jaGVjayhzb25hcnF1YmVfaXNzdWVzLndpdGgoKSwgbnNhbXBsZXMgPSAyMDAsIHR5cGUgPSAiYmFycyIpICsgeGxpbSgtMSwgMTUpCmBgYAoKIyMjIyBTdW1tYXJ5CgpgYGB7ciBiYXNlLXN1bW1hcnl9CnN1bW1hcnkoc29uYXJxdWJlX2lzc3Vlcy53aXRoKCkpCmBgYAoKIyMjIyBTYW1wbGluZyBwbG90cwoKYGBge3IgYmFzZS1wbG90fQpwbG90KHNvbmFycXViZV9pc3N1ZXMud2l0aCgpLCBhc2sgPSBGQUxTRSkKYGBgCgojIyBNb2RlbCBwcmVkaWN0b3IgZXh0ZW5zdGlvbnMgey50YWJzZXR9CgpgYGB7ciBtby1wcmlvcnN9CiMgZGVmYXVsdCBwcmlvciBmb3IgbW9ub3RvbmljIHByZWRpY3RvcgplZGx2bF9wcmlvciA8LSBwcmlvcihkaXJpY2hsZXQoMiksIGNsYXNzID0gInNpbW8iLCBjb2VmID0gIm1vZWR1Y2F0aW9uX2xldmVsMSIpCmBgYAoKIyMjIE9uZSB2YXJpYWJsZSB7LnRhYnNldH0KCmBgYHtyIG1vZGVsLWV4dGVuc2lvbi0xLCB3YXJuaW5nPUZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KbG9vX3Jlc3VsdCA8LSBsb28oCiAgIyBCZW5jaG1hcmsgbW9kZWwocykKICBzb25hcnF1YmVfaXNzdWVzLndpdGgoKSwKICAjIE5ldyBtb2RlbChzKQogIHNvbmFycXViZV9pc3N1ZXMud2l0aCgibW9kaWZpZWRfbGluZXMiKSwKICBzb25hcnF1YmVfaXNzdWVzLndpdGgoIndvcmtfZG9tYWluIiksCiAgc29uYXJxdWJlX2lzc3Vlcy53aXRoKCJ3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcucyIpLAogIHNvbmFycXViZV9pc3N1ZXMud2l0aCgid29ya19leHBlcmllbmNlX2phdmEucyIpLAogIHNvbmFycXViZV9pc3N1ZXMud2l0aCgiZWR1Y2F0aW9uX2ZpZWxkIiksCiAgc29uYXJxdWJlX2lzc3Vlcy53aXRoKCJtbyhlZHVjYXRpb25fbGV2ZWwpIiwgZWRsdmxfcHJpb3IpLAogIHNvbmFycXViZV9pc3N1ZXMud2l0aCgid29ya3BsYWNlX3BlZXJfcmV2aWV3IiksCiAgc29uYXJxdWJlX2lzc3Vlcy53aXRoKCJ3b3JrcGxhY2VfdGRfdHJhY2tpbmciKSwKICBzb25hcnF1YmVfaXNzdWVzLndpdGgoIndvcmtwbGFjZV9wYWlyX3Byb2dyYW1taW5nIiksCiAgc29uYXJxdWJlX2lzc3Vlcy53aXRoKCJ3b3JrcGxhY2VfY29kaW5nX3N0YW5kYXJkcyIpLAogIHNvbmFycXViZV9pc3N1ZXMud2l0aCgic2NlbmFyaW8iKSwKICBzb25hcnF1YmVfaXNzdWVzLndpdGgoImdyb3VwIikKKQoKCmBgYAoKIyMjIyBDb21wYXJpc29uCgpgYGB7ciBtb2RlbC1leHRlbnNpb24tMS1zdW0sIHdhcm5pbmc9RkFMU0V9Cmxvb19yZXN1bHRbMl0KYGBgCgojIyMjIERpYWdub3N0aWNzCgpgYGB7ciBtb2RlbC1leHRlbnNpb24tMS1kaWcsIHdhcm5pbmc9RkFMU0V9Cmxvb19yZXN1bHRbMV0KYGBgCgojIyBDYW5kaWRhdGUgbW9kZWxzIHsudGFic2V0fQoKV2UgaW5zcGVjdCBzb21lIG9mIG91ciB0b3AgcGVyZm9ybWluZyBtb2RlbHMuIAoKQWxsIG1vZGVscyBzZWVtcyB0byBoYXZlIHNhbXBsZWQgbmljZWx5IChyaGF0ID0gMSBhbmQgZmx1ZmZ5IHBsb3RzKSB0aGV5IGFsc28gaGF2ZSBhYm91dCB0aGUgc2FtZSBmaXQgdG8gdGhlIGRhdGEgYW5kIHNpbWlsYXIgZXN0aW1hdGVzIGZvciB0aGUgaGlnaF9kZWJ0X3ZlcnNpb24gYmV0YSBwYXJhbWV0ZXIuCgojIyMgc29uYXJxdWJlX2lzc3VlczAgIHsudGFic2V0fQoKV2Ugc2VsZWN0IHRoZSBzaW1wbGVzdCBtb2RlbCBhcyBhIGJhc2VsaW5lLgoKYGBge3Igc29uYXJxdWJlX2lzc3VlczAsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQpzb25hcnF1YmVfaXNzdWVzMCA8LSBicm0oCiAgInNvbmFycXViZV9pc3N1ZXMgfiAxICsgaGlnaF9kZWJ0X3ZlcnNpb24gKyAoMSB8IHNlc3Npb24pIiwKICBwcmlvciA9IGMoCiAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gImIiKSwKICAgIHByaW9yKG5vcm1hbCgxLjUsIDEpLCBjbGFzcyA9ICJJbnRlcmNlcHQiKSwKICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcyA9ICJzZCIpLAogICAgcHJpb3IoZ2FtbWEoMC4wMSwgMC4wMSksIGNsYXNzID0gInNoYXBlIikKICApLAogIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgZGF0YSA9IGQuYm90aF9jb21wbGV0ZWQsCiAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGEgPSAwLjk3KSwKICBmaWxlID0gImZpdHMvc29uYXJxdWJlX2lzc3VlczAiLAogIGZpbGVfcmVmaXQgPSAib25fY2hhbmdlIiwKICBzZWVkID0gMjAyMTA0MjEKKQoKYGBgCgojIyMjIFN1bW1hcnkKCmBgYHtyIHNvbmFycXViZV9pc3N1ZXMwLXN1bX0Kc3VtbWFyeShzb25hcnF1YmVfaXNzdWVzMCkKYGBgCgojIyMjIFJhbmRvbSBlZmZlY3RzCgpgYGB7ciBzb25hcnF1YmVfaXNzdWVzMC1yYW5lZmZ9CnJhbmVmKHNvbmFycXViZV9pc3N1ZXMwKQpgYGAKCiMjIyMgU2FtcGxpbmcgcGxvdHMKCmBgYHtyIHNvbmFycXViZV9pc3N1ZXMwLXBsb3R9CnBsb3Qoc29uYXJxdWJlX2lzc3VlczAsIGFzayA9IEZBTFNFKQpgYGAKCiMjIyMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2sKCmBgYHtyIHNvbmFycXViZV9pc3N1ZXMwLXBwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwcF9jaGVjayhzb25hcnF1YmVfaXNzdWVzMCwgbnNhbXBsZXMgPSAyMDAsIHR5cGUgPSAiYmFycyIpICArIHhsaW0oLTEsIDE1KQpgYGAKCiMjIyBzb25hcnF1YmVfaXNzdWVzMSAgey50YWJzZXR9CldlIHNlbGVjdCB0aGUgYmVzdCBwZXJmb3JtaW5nIG1vZGVsIHdpdGggb25lIHZhcmlhYmxlLgogIApgYGB7ciBzb25hcnF1YmVfaXNzdWVzMSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9CnNvbmFycXViZV9pc3N1ZXMxIDwtIGJybSgKICAic29uYXJxdWJlX2lzc3VlcyB+IDEgKyBoaWdoX2RlYnRfdmVyc2lvbiArICgxIHwgc2Vzc2lvbikgKyBncm91cCIsCiAgcHJpb3IgPSBjKAogICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9ICJiIiksCiAgICBwcmlvcihub3JtYWwoMS41LCAxKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3MgPSAic2QiKSwKICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9ICJzaGFwZSIpCiAgKSwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBkLmJvdGhfY29tcGxldGVkLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45NyksCiAgZmlsZSA9ICJmaXRzL3NvbmFycXViZV9pc3N1ZXMxIiwKICBmaWxlX3JlZml0ID0gIm9uX2NoYW5nZSIsCiAgc2VlZCA9IDIwMjEwNDIxCikKCmBgYAoKIyMjIyBTdW1tYXJ5CgpgYGB7ciBzb25hcnF1YmVfaXNzdWVzMS1zdW19CnN1bW1hcnkoc29uYXJxdWJlX2lzc3VlczEpCmBgYAoKIyMjIyBSYW5kb20gZWZmZWN0cwoKYGBge3Igc29uYXJxdWJlX2lzc3VlczEtcmFuZWZmfQpyYW5lZihzb25hcnF1YmVfaXNzdWVzMSkKYGBgCgojIyMjIFNhbXBsaW5nIHBsb3RzCgpgYGB7ciBzb25hcnF1YmVfaXNzdWVzMS1wbG90fQpwbG90KHNvbmFycXViZV9pc3N1ZXMxLCBhc2sgPSBGQUxTRSkKYGBgCgojIyMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNrCgpgYGB7ciBzb25hcnF1YmVfaXNzdWVzMS1wcCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcHBfY2hlY2soc29uYXJxdWJlX2lzc3VlczEsIG5zYW1wbGVzID0gMjAwLCB0eXBlID0gImJhcnMiKSArIHhsaW0oLTEsIDE1KQpgYGAKCiMjIEZpbmFsIE1vZGVsIApBbGwgY2FuZGlkYXRlIG1vZGVscyBsb29rIG5pY2UsIG5vbmUgaXMgc2lnbmlmaWNhbnRseSBiZXR0ZXIgdGhhbiB0aGUgb3RoZXJzLCB3ZSB3aWxsIHByb2NlZWQgdGhlIHNpbXBsZXN0IG1vZGVsOiBgc29uYXJxdWJlX2lzc3VlczBgCgojIyMgVmFyaWF0aW9ucyB7LnRhYnNldH0KV2Ugd2lsbCB0cnkgYSBmZXcgZGlmZmVyZW50IHZhcmlhdGlvbnMgb2YgdGhlIHNlbGVjdGVkIGNhbmRpZGF0ZSBtb2RlbC4KCiMjIyMgQWxsIGRhdGEgcG9pbnRzIHsudGFic2V0fQoKU29tZSBwYXJ0aWNpcGFudHMgZGlkIG9ubHkgY29tcGxldGUgb25lIHNjZW5hcmlvLiBUaG9zZSBoYXMgYmVlbiBleGNsdWRlZCBmcm9tIHRoZSBpbml0aWFsIGRhdGFzZXQgdG8gaW1wcm92ZSBzYW1wbGluZyBvZiB0aGUgbW9kZWxzLiBXZSBkbyBob3dldmVyIHdhbnQgdG8gdXNlIGFsbCBkYXRhIHdlIGNhbiBhbmQgd2lsbCB0aGVyZWZvcmUgdHJ5IHRvIGZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgY29tcGxldGUgZGF0YXNldC4KCmBgYHtyIHZhcmlhdGlvbi5hbGwsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQpzb25hcnF1YmVfaXNzdWVzMC5hbGwgPC0gYnJtKAogICJzb25hcnF1YmVfaXNzdWVzIH4gMSArIGhpZ2hfZGVidF92ZXJzaW9uICsgKDEgfCBzZXNzaW9uKSIsCiAgcHJpb3IgPSBjKAogICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9ICJiIiksCiAgICBwcmlvcihub3JtYWwoMS41LCAxKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3MgPSAic2QiKSwKICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9ICJzaGFwZSIpCiAgKSwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBhcy5kYXRhLmZyYW1lKGQuY29tcGxldGVkKSwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOTcpLAogIGZpbGUgPSAiZml0cy9zb25hcnF1YmVfaXNzdWVzMC5hbGwiLAogIGZpbGVfcmVmaXQgPSAib25fY2hhbmdlIiwKICBzZWVkID0gMjAyMTA0MjEKKQpgYGAKCiMjIyMjIFN1bW1hcnkKCmBgYHtyIHZhcmlhdGlvbi5hbGwtc3VtfQpzdW1tYXJ5KHNvbmFycXViZV9pc3N1ZXMwLmFsbCkKYGBgCgojIyMjIyBSYW5kb20gZWZmZWN0cwoKYGBge3IgdmFyaWF0aW9uLmFsbC1yYW5lZmZ9CnJhbmVmKHNvbmFycXViZV9pc3N1ZXMwLmFsbCkKYGBgCgojIyMjIyBTYW1wbGluZyBwbG90cwoKYGBge3IgdmFyaWF0aW9uLmFsbC1wbG90fQpwbG90KHNvbmFycXViZV9pc3N1ZXMwLmFsbCwgYXNrID0gRkFMU0UpCmBgYAoKIyMjIyMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2sKCmBgYHtyIHZhcmlhdGlvbi5hbGwtcHAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBwX2NoZWNrKHNvbmFycXViZV9pc3N1ZXMwLmFsbCwgbnNhbXBsZXMgPSAyMDAsIHR5cGUgPSAiYmFycyIpICsgeGxpbSgtMSwgMTUpCmBgYAoKIyMjIyBXaXRoIGV4cGVyaWVuY2UgcHJlZGljdG9yIHsudGFic2V0fQoKQXMgaW5jbHVkaW5nIGFsbCBkYXRhIHBvaW50cyBkaWRuJ3QgaGFybSB0aGUgbW9kZWwgd2Ugd2lsbCBjcmVhdGUgdGhpcyB2YXJpYW50IHdpdGggYWxsIGRhdGEgcG9pbnRzIGFzIHdlbGwuCgpUaGlzIHZhcmlhdGlvbiBpbmNsdWRlcyBgd29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nLnNgIHByZWRpY3RvcnMgYXMgaXQgY2FuIGdpdmUgZnVydGhlciBpbnNpZ2h0IGludG8gaG93IGV4cGVyaWVuY2UgcGxheSBhIGZhY3RvciBpbiB0aGUgZWZmZWN0IHdlIHRyeSB0byBtZWFzdXJlLiBUaGlzIGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50IGFzIG91ciBzYW1wbGluZyBzaGV3ZWQgdG93YXJkcyBjb250YWluaW5nIGxlc3MgZXhwZXJpZW5jZWQgZGV2ZWxvcGVyIHRoYW4gdGhlIHBvcHVsYXRpb24gYXQgbGFyZ2UuCgpgYGB7ciB2YXJpYXRpb24uYWxsLmV4cCwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9Cgpzb25hcnF1YmVfaXNzdWVzMC5hbGwuZXhwIDwtIGJybSgKICAic29uYXJxdWJlX2lzc3VlcyB+IDEgKyBoaWdoX2RlYnRfdmVyc2lvbiArICgxIHwgc2Vzc2lvbikgKyB3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcucyIsCiAgcHJpb3IgPSBjKAogICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9ICJiIiksCiAgICBwcmlvcihub3JtYWwoMS41LCAxKSwgY2xhc3MgPSAiSW50ZXJjZXB0IiksCiAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3MgPSAic2QiKSwKICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9ICJzaGFwZSIpCiAgKSwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBhcy5kYXRhLmZyYW1lKGQuY29tcGxldGVkKSwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOTkpLAogIGZpbGUgPSAiZml0cy9zb25hcnF1YmVfaXNzdWVzMC5hbGwuZXhwIiwKICBmaWxlX3JlZml0ID0gIm9uX2NoYW5nZSIsCiAgc2VlZCA9IDIwMjEwNDIxCikKCmBgYAoKIyMjIyMgU3VtbWFyeQoKYGBge3IgdmFyaWF0aW9uLmFsbC5leHAtc3VtfQpzdW1tYXJ5KHNvbmFycXViZV9pc3N1ZXMwLmFsbC5leHApCmBgYAoKIyMjIyMgUmFuZG9tIGVmZmVjdHMKCmBgYHtyIHZhcmlhdGlvbi5hbGwuZXhwLXJhbmVmZn0KcmFuZWYoc29uYXJxdWJlX2lzc3VlczAuYWxsLmV4cCkKYGBgCgojIyMjIyBMb28gY29tcGFyaXNvbgoKYGBge3IgdmFyaWF0aW9uLmFsbC5leHAtbG9vLCB3YXJuaW5nPUZBTFNFfQpsb28oCiAgc29uYXJxdWJlX2lzc3VlczAuYWxsLAogIHNvbmFycXViZV9pc3N1ZXMwLmFsbC5leHAKKQpgYGAKCiMjIyMjIFNhbXBsaW5nIHBsb3RzCgpgYGB7ciB2YXJpYXRpb24uYWxsLmV4cC1wbG90fQpwbG90KHNvbmFycXViZV9pc3N1ZXMwLmFsbC5leHAsIGFzayA9IEZBTFNFKQpgYGAKCiMjIyMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNrCgpgYGB7ciB2YXJpYXRpb24uYWxsLmV4cC1wcCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcHBfY2hlY2soc29uYXJxdWJlX2lzc3VlczAuYWxsLmV4cCwgbnNhbXBsZXMgPSAyMDAsIHR5cGUgPSAiYmFycyIpICsgeGxpbSgtMSwgMTUpCmBgYAoKCiMjIyBGaW5hbCBtb2RlbAoqIEZpdHRpbmcgdGhlIG1vZGVsIHRvIGFsbCBkYXRhIHBvaW50IGRpZCBub3Qgc2lnbmlmaWNhbnRseSBkYW1hZ2UgdGhlIG1vZGVsIGFuZCB3aWxsIGJlIHVzZWQgYXMgaXMgYSBtb3JlIGZhaXIgcmVwcmVzZW50YXRpb24gb2YgcmVhbGl0eS4KKiBBZGRpbmcgdGhlIGV4cGVyaWVuY2UgcHJlZGljdG9ycyBkaWQgbm90IHNpZ25pZmljYW50bHkgZGFtYWdlIHRoZSBtb2RlbCBhbmQgd2lsbCBiZSB1c2VkIGFzIGl0IHByb3ZpZGVzIHVzZWZ1bCBpbnNpZ2h0LgoKVGhpcyBtZWFucyB0aGF0IG91ciBmaW5hbCBtb2RlbCwgd2l0aCBhbGwgZGF0YSBwb2ludHMgYW5kIGV4cGVyaWVuY2UgcHJlZGljdG9ycywgaXMgYHNvbmFycXViZV9pc3N1ZXMwLmFsbC5leHBgCgojIyBJbnRlcnByZXRpbmcgdGhlIG1vZGVsClRvIGJlZ2luIGludGVycHJldGluZyB0aGUgbW9kZWwgd2UgbG9vayBhdCBob3cgaXQncyBwYXJhbWV0ZXJzIHdlcmUgZXN0aW1hdGVkLiBBcyBvdXIgcmVzZWFyY2ggaXMgZm9jdXNlZCBvbiBob3cgdGhlIG91dGNvbWUgb2YgdGhlIG1vZGVsIGlzIGVmZmVjdGVkIHdlIHdpbGwgbWFpbmx5IGFuYWx5emUgdGhlICRcYmV0YSQgcGFyYW1ldGVycy4KCiMjIyAkXGJldGEkIHBhcmFtZXRlcnMKYGBge3IgaW50ZXJwcmV0LWJldGEtcGxvdCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbWNtY19hcmVhcyhzb25hcnF1YmVfaXNzdWVzMC5hbGwuZXhwLCBwYXJzID0gYygiYl9oaWdoX2RlYnRfdmVyc2lvbmZhbHNlIiwgImJfd29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nLnMiKSwgcHJvYiA9IDAuOTUpICsgc2NhbGVfeV9kaXNjcmV0ZSgpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscz1jKCJIaWdoIGRlYnQgdmVyc2lvbjogZmFsc2UiLCAiUHJvZmVzc2lvbmFsIHByb2dyYW1taW5nIGV4cGVyaWVuY2UiKSkgKwogIGdndGl0bGUoIkJldGEgcGFyYW1ldGVycyBkZW5zaXRpZXMgaW4gc29uYXJxdWJlIGlzc3VlcyBtb2RlbCIsIHN1YnRpdGxlID0gIlNoYWRlZCByZWdpb24gbWFya3MgOTUlIG9mIHRoZSBkZW5zaXR5LiBMaW5lIG1hcmtzIHRoZSBtZWRpYW4iKQpgYGAKCgojIyMgRWZmZWN0cyBzaXplcwoKYGBge3IgZWZmZWN0LXNpemUtMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2NhbGVfcHJvZ3JhbW1pbmdfZXhwZXJpZW5jZSA8LSBmdW5jdGlvbih4KSB7CiAgKHggLSBtZWFuKGQuY29tcGxldGVkJHdvcmtfZXhwZXJpZW5jZV9wcm9ncmFtbWluZykpLyBzZChkLmNvbXBsZXRlZCR3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcpCn0KdW5zY2FsZV9wcm9ncmFtbWluZ19leHBlcmllbmNlIDwtIGZ1bmN0aW9uKHgpIHsKICB4ICogc2QoZC5jb21wbGV0ZWQkd29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nKSArIG1lYW4oZC5jb21wbGV0ZWQkd29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nKQp9Cgpwb3N0X3NldHRpbmdzIDwtIGV4cGFuZC5ncmlkKAogIGhpZ2hfZGVidF92ZXJzaW9uID0gYygiZmFsc2UiLCAidHJ1ZSIpLAogIHNlc3Npb24gPSBOQSwKICB3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcucyA9IHNhcHBseShjKDAsIDMsIDEwLCAyNSwgNDApLCBzY2FsZV9wcm9ncmFtbWluZ19leHBlcmllbmNlKQopCgpwb3N0IDwtIHBvc3Rlcmlvcl9wcmVkaWN0KHNvbmFycXViZV9pc3N1ZXMwLmFsbC5leHAsIG5ld2RhdGEgPSBwb3N0X3NldHRpbmdzKSAlPiUKICBtZWx0KHZhbHVlLm5hbWUgPSAiZXN0aW1hdGUiLCB2YXJuYW1lcyA9IGMoInNhbXBsZV9udW1iZXIiLCAic2V0dGluZ3NfaWQiKSkgJT4lCiAgbGVmdF9qb2luKAogICAgcm93aWRfdG9fY29sdW1uKHBvc3Rfc2V0dGluZ3MsIHZhcj0gInNldHRpbmdzX2lkIiksCiAgICBieSA9ICJzZXR0aW5nc19pZCIKICApICU+JQogIG11dGF0ZSh3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcgPSB1bnNjYWxlX3Byb2dyYW1taW5nX2V4cGVyaWVuY2Uod29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nLnMpKSAlPiUKICBzZWxlY3QoCiAgICBlc3RpbWF0ZSwKICAgIGhpZ2hfZGVidF92ZXJzaW9uLAogICAgd29ya19leHBlcmllbmNlX3Byb2dyYW1taW5nCiAgKSU+JQogIG11dGF0ZShlc3RpbWF0ZSA9IGVzdGltYXRlKQoKZ2dwbG90KHBvc3QsIGFlcyh4PWVzdGltYXRlLCBmaWxsID0gaGlnaF9kZWJ0X3ZlcnNpb24pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UyIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgbmFtZSA9ICJEZWJ0IHZlcnNpb24iLAogICAgbGFiZWxzID0gYygiTG93IGRlYnQiLCAiSGlnaCBkZWJ0IiksCiAgICAgIHZhbHVlcyA9IGMoImxpZ2h0Ymx1ZSIsICJkYXJrYmx1ZSIpCiAgKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcpKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNvbmFyUXViZSBpc3N1ZXMgaW50cm9kdWNlZCAvIHllYXJzIG9mIHByb2dyYW1taW5nIGV4cGVyaWVuY2UiLAogICAgc3VidGl0bGUgPSAiRXN0aW1hdGVkIGZvciBmaXZlIGRpZmZlcmVudCBleHBlcmllbmNlIGxldmVscyIsCiAgICB4ID0gIklzc3VlZCBpbnRyb2R1Y2VkIiwKICAgIHkgPSAiSW5jaWRlbmNlIHJhdGUiCiAgKSArIAogIHhsaW0oLTEsIDEwKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0xLDcpLCBicmVha3MgPSBjKDAsMSwyLDMsNCw1LDYsNyksIGxhYmVscyA9IGMoIjAiLCIxIiwiMiIsIjMiLCI0IiwiNSIsIjYiLCI3IikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gTlVMTCwgYnJlYWtzID0gYyg1MDAsMTUwMCwyNTAwKSwgbGFiZWxzID0gYygiMTAlIiwiMzAlIiwiNTAlIikpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgpgYGAKCgpgYGB7ciBlZmZlY3Qtc2l6ZS1kaWZmLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpwb3N0LmRpZmYgPC0gcG9zdCAlPiUgZmlsdGVyKGhpZ2hfZGVidF92ZXJzaW9uID09ICJ0cnVlIikKcG9zdC5kaWZmJGVzdGltYXRlID0gcG9zdC5kaWZmJGVzdGltYXRlIC0gIGZpbHRlcihwb3N0LCBoaWdoX2RlYnRfdmVyc2lvbiA9PSAiZmFsc2UiKSRlc3RpbWF0ZQoKZ2dwbG90KHBvc3QuZGlmZiwgYWVzKHg9ZXN0aW1hdGUpKSArCiAgZ2VvbV9ib3hwbG90KHF1YW50aWxlX2xpbmVzID0gVFJVRSwgcXVhbnRpbGVfZnVuID0gaGRpLCB2bGluZV9saW5ldHlwZSA9IDIpICsKICB4bGltKC03LCA3KSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcpKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNvbmFyUXViZSBpc3N1ZXMgaW50cm9kdWNlZCBkaWZmZXJlbmNlIC8geWVhcnMgb2YgcHJvZ3JhbW1pbmcgZXhwZXJpZW5jZSIsCiAgICBzdWJ0aXRsZSA9ICJEaWZmZXJlbmNlIGFzOiBoaWdoIGRlYnQgaXNzdWVzIC0gbG93IGRlYnQgaXNzdWVzIiwKICAgIHggPSAiSXNzdWVzICMgZGlmZmVyZW5jZSIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gTlVMTCkKYGBgCgpgYGB7ciBzdHVmZiwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9CnByaW50KCJBbGw6IikKbWVhbihwb3N0LmRpZmYkZXN0aW1hdGUpCgpwcmludCgiMyB5ZWFyczoiKQptZWFuKHBvc3QuZGlmZiAlPiUgZmlsdGVyKHdvcmtfZXhwZXJpZW5jZV9wcm9ncmFtbWluZyA9PSAzKSAlPiUgcHVsbChlc3RpbWF0ZSkpCgpwcmludCgiMjUgeWVhcnM6IikKbWVhbihwb3N0LmRpZmYgJT4lIGZpbHRlcih3b3JrX2V4cGVyaWVuY2VfcHJvZ3JhbW1pbmcgPT0gMjUpICU+JSBwdWxsKGVzdGltYXRlKSkKYGBgCgpJbiB0aGUgY29udGV4dCBvZiB0aGUgYXNzaWdubWVudCB0aGUgcGFydGljaXBhbnQgd2VyZSBnaXZlbiwgcHJlZXhpc3RpbmcgdGVjaG5pY2FsIGRlYnQgY2F1c2VkIGRldmVsb3BlcnMgdG8gb24gYXZlcmFnZSBpbnRyb2R1Y2UgYDEuMThgIHNvbmFycXViZSBpc3N1ZXMgbW9yZS4gVGhlIGVmZmVjdCB2YXJpZXMgd2l0aCB0aGUgcHJvZmVzc2lvbmFsIHByb2dyYW1taW5nIGV4cGVyaWVuY2Ugb2YgdGhlIGRldmVsb3BlciB3aXRoIGFuIGF2ZXJhZ2Ugb2YgYDEuMzNgIGZvciB0aG9zZSB3aXRoIDMgeWVhcnMgb2YgZXhwZXJpZW5jZSBhbmQgYW4gYXZlcmFnZSBvZiBgMC44N2AgZm9yIHRob3NlIHdpdGggMjUgeWVhcnMgb2YgZXhwZXJpZW5jZS4=